package com.apptonelabs.vphonevisor;
/*
 * Copyright Apptonelabs. All rights reserved. NetEnrich
 * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

import com.apptonelabs.vphonevisor.netty.VPhoneVisorProtocolCodecFactory;

/**
 * NEProbe Listener.</br> It contains WinMon Listener and Discovery Lister.</br>
 * Its better to run only one JVM in the Box.
 */
public class VPhoneVisorProcess implements Daemon {
	private static Logger log = Logger.getLogger(VPhoneVisorProcess.class.getName());

	// Default values for the Runtime parameters
	private int NIO_IO_THREADS = 256;
	private int MINA_LISTEN_QUEUE_LEN = 256; 
	private static Object TERMINATOR = new Object();
	private static int atxdPort = 0;
	
	// Server Handelr
	Channel _server = null;

	/**
	 * @see org.apache.commons.daemon.Daemon#init(org.apache.commons.daemon.DaemonContext)
	 */
	public void init(DaemonContext arg0) throws Exception {
		// Invoke WinMonitoring as a Thread
		try {
			this.invokeATXd();
		} catch (Exception e) {
			log.log(Level.SEVERE, "Not able to start the Winmon Process", e);
		}
	}

	/**
	 * Start the WinMon server listener. By default it runs at 4442
	 * 
	 * @throws Exception
	 */
	public void invokeATXd() throws Exception {
		String confDir = System.getProperty("atxd.dir");
		if (confDir == null || confDir.length() < 1) {
			log.severe("Config file does not exists : configFile =" + confDir);
		}
		try {
			String fileName = confDir + File.separator + "atxd.conf";
			Properties properties = loadProperties(fileName);
			try {
				atxdPort = Integer.parseInt(properties.getProperty("atxd.bind.port"));
			} catch (Exception e) {
				log.severe("Not able to load the property atxd.bind.port");
				return;
			}
			if (atxdPort <= 0) {
				log.severe("Invalid bind port received = " + atxdPort);
				return;
			}

			try {
				NIO_IO_THREADS = Integer.parseInt(properties.getProperty("atxd.io.thread.count"));
			} catch (Exception e) {
				log.severe("Error reading the atxd.io.thread.count. Default value=" + NIO_IO_THREADS);
			}

			try {
				MINA_LISTEN_QUEUE_LEN = Integer.parseInt(properties.getProperty("atxd.accept.queue.count"));
			} catch (Exception e) {
				log.severe("Error reading the atxd.accept.queue.count Default value="
								+ MINA_LISTEN_QUEUE_LEN);
			}
		} catch (Exception e) {
			log.log(Level.SEVERE, "Not able to Start the ATXd Daemon. Error="	+ e.getMessage(), e);
		}
	}
	
	/**
	 * @param fileName
	 * @return
	 */
	private Properties loadProperties(String fileName) {
		Properties properties = new Properties();
		InputStream inStream = null;
		try {
			File file = new File(fileName);
			if (!file.exists()) {
				log.severe("Config file does not exists : configFile = "
						+ fileName);
			}
			inStream = new FileInputStream(fileName);
			properties.load(inStream);
		} catch (Exception e) {
			log.severe("Unbale to load the properties file " + e.getMessage());
		} finally {
			if (inStream != null) {
				try {
					inStream.close();
				} catch (IOException e) {
					log.fine(e.getMessage());
				}
			}
		}
		return properties;
	}

	@Override
	public void destroy() {
		try {
			this.stop();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void start() throws Exception {
		try {
			Class.forName("com.apptonelabs.vphonevisor.netty.VPhoneVisorProtocolCodecFactory");
			ServerBootstrap bootstrap = new ServerBootstrap(
					new NioServerSocketChannelFactory(Executors
							.newCachedThreadPool(), Executors
							.newCachedThreadPool()));

			// Set up the pipeline factory.
			bootstrap.setPipelineFactory(new VPhoneVisorProtocolCodecFactory());

			// Bind and start to accept incoming connections.
			_server = bootstrap.bind(new InetSocketAddress(Inet4Address.getByName("127.0.0.1"), atxdPort));

			log.log(Level.SEVERE, "ATXd (NETTY) running @ " + atxdPort);
		} catch (NoClassDefFoundError err) {
			log.log(Level.SEVERE, "Not able to find com.apptonelabs.vphonevisor.netty.VPhoneVisorProtocolCodecFactory" +
					" ATXd Can't start...!!!", err);
		} catch (Exception e) {
			log.log(Level.SEVERE, "Not able to listen @ " + atxdPort, e);
		}
		
		// Wait for the Kill
		synchronized(TERMINATOR) {
			TERMINATOR.wait();
		}
	}

	@Override
	public void stop() throws Exception {
		// Close server first
		try {
			_server.close();
		} catch (Exception e) {
			// ignore
		}
		synchronized(TERMINATOR) {
			TERMINATOR.notifyAll();
		}
	}
}
